﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Publicuse.Util
{
    /// <summary>
    /// DataTable转换成实体类
    /// </summary>
    public class DataTableUtil
    {

        #region DataTable转换成实体类

        public static IList<T> convertToList<T>(DataTable dt) where T : class, new()
        {
            //定义集合 
            List<T> list = new List<T>();

            //定义一个临时变量 
            string tempName = string.Empty;
            //遍历DataTable中所有的数据行  
            foreach (DataRow dr in dt.Rows)
            {
                T t = new T();
                //获得此模型的公共属性 
                PropertyInfo[] propertys = t.GetType().GetProperties();
                //遍历该对象的所有属性 
                foreach (PropertyInfo pi in propertys)
                {
                    tempName = pi.Name;//将属性名称赋值给临时变量   
                    //检查DataTable是否包含此列（列名==对象的属性名）     
                    if (dt.Columns.Contains(tempName))
                    {
                        // 判断此属性是否有Setter   
                        //if (!pi.CanWrite) continue;//该属性不可写，直接跳出   
                        //取值   
                        object value = dr[tempName];
                        try
                        {
                            //如果非空，则赋给对象的属性   
                            if (value != DBNull.Value)

                                //time类型转换为string
                                if (value is TimeSpan)
                                    pi.SetValue(t, value.ToString(), null);
                                else if (value is Double)
                                    pi.SetValue(t, Convert.ToDouble(value), null);
                                else if (value is Int32)
                                    pi.SetValue(t, Convert.ToInt32(value), null);
                                else if (value is Int64)
                                    pi.SetValue(t, Convert.ToInt64(value), null);
                                else if (value is DateTime)
                                    pi.SetValue(t, Convert.ToDateTime(value), null);
                                else
                                    pi.SetValue(t, value.ToString(), null);
                        }
                        catch (Exception ex)
                        {
                            continue;
                        }

                    }
                }
                //对象添加到泛型集合中 
                list.Add(t);
            }
            return list;
        }
        #endregion

        #region DataSet转换为实体类
        /// <summary>
        /// DataSet转换为实体类
        /// </summary>
        /// <typeparam name="T">实体类</typeparam>
        /// <param name="p_DataSet">DataSet</param>
        /// <param name="p_TableIndex">待转换数据表索引</param>
        /// <returns>实体类</returns>
        public static T DataSetToEntity<T>(DataSet p_DataSet, int p_TableIndex)
        {
            if (p_DataSet == null || p_DataSet.Tables.Count < 0)
                return default(T);
            if (p_TableIndex > p_DataSet.Tables.Count - 1)
                return default(T);
            if (p_TableIndex < 0)
                p_TableIndex = 0;
            if (p_DataSet.Tables[p_TableIndex].Rows.Count <= 0)
                return default(T);

            DataRow p_Data = p_DataSet.Tables[p_TableIndex].Rows[0];
            // 返回值初始化
            T _t = (T)Activator.CreateInstance(typeof(T));
            PropertyInfo[] propertys = _t.GetType().GetProperties();
            foreach (PropertyInfo pi in propertys)
            {
                if (p_DataSet.Tables[p_TableIndex].Columns.IndexOf(pi.Name.ToUpper()) != -1 && p_Data[pi.Name.ToUpper()] != DBNull.Value)
                {
                    pi.SetValue(_t, p_Data[pi.Name.ToUpper()], null);
                }
                else
                {
                    pi.SetValue(_t, null, null);
                }
            }
            return _t;
        }

        #endregion

        #region DataSet转换为实体列表
        /// <summary>
        /// DataSet转换为实体列表
        /// </summary>
        /// <typeparam name="T">实体类</typeparam>
        /// <param name="p_DataSet">DataSet</param>
        /// <param name="p_TableIndex">待转换数据表索引</param>
        /// <returns>实体类列表</returns>
        public static IList<T> DataSetToEntityList<T>(DataSet p_DataSet, int p_TableIndex)
        {
            if (p_DataSet == null || p_DataSet.Tables.Count < 0)
                return default(IList<T>);
            if (p_TableIndex > p_DataSet.Tables.Count - 1)
                return default(IList<T>);
            if (p_TableIndex < 0)
                p_TableIndex = 0;
            if (p_DataSet.Tables[p_TableIndex].Rows.Count <= 0)
                return default(IList<T>);
            DataTable p_Data = p_DataSet.Tables[p_TableIndex];
            // 返回值初始化
            IList<T> result = new List<T>();
            foreach (DataRow dr in p_Data.Rows)
            {
                T _t = (T)Activator.CreateInstance(typeof(T));
                PropertyInfo[] propertys = _t.GetType().GetProperties();
                foreach (PropertyInfo pi in propertys)
                {
                    if (p_Data.Columns.IndexOf(pi.Name.ToUpper()) != -1 && dr[pi.Name.ToUpper()] != DBNull.Value)
                        pi.SetValue(_t, dr[pi.Name.ToUpper()], null);
                    else
                        pi.SetValue(_t, null, null);
                }
                result.Add(_t);
            }
            return result;
        }

        #endregion

        #region DataReader转实体
        /// <summary>  
        /// DataReader转实体  
        /// </summary>  
        /// <typeparam name="T">数据类型</typeparam>  
        /// <param name="dr">DataReader</param>  
        /// <returns>实体</returns>  
        public static T DataReaderToModel<T>(IDataReader dr) where T : new()
        {
            T t = new T();
            if (dr == null) return default(T);
            using (dr)
            {
                if (dr.Read())

                {
                    // 获得此模型的公共属性  
                    PropertyInfo[] propertys = t.GetType().GetProperties();
                    List<string> listFieldName = new List<string>(dr.FieldCount);
                    for (int i = 0; i < dr.FieldCount; i++)
                    {
                        listFieldName.Add(dr.GetName(i).ToLower());
                    }

                    foreach (PropertyInfo p in propertys)
                    {
                        string columnName = p.Name;
                        if (listFieldName.Contains(columnName.ToLower()))
                        {
                            // 判断此属性是否有Setter或columnName值是否为空  
                            object value = dr[columnName];
                            if (!p.CanWrite || value is DBNull || value == DBNull.Value) continue;
                            try
                            {
                                #region SetValue
                                switch (p.PropertyType.ToString())
                                {
                                    case "System.String":
                                        p.SetValue(t, Convert.ToString(value), null);
                                        break;
                                    case "System.Int32":
                                        p.SetValue(t, Convert.ToInt32(value), null);
                                        break;
                                    case "System.DateTime":
                                        p.SetValue(t, Convert.ToDateTime(value), null);
                                        break;
                                    case "System.Boolean":
                                        p.SetValue(t, Convert.ToBoolean(value), null);
                                        break;
                                    case "System.Double":
                                        p.SetValue(t, Convert.ToDouble(value), null);
                                        break;
                                    case "System.Decimal":
                                        p.SetValue(t, Convert.ToDecimal(value), null);
                                        break;
                                    default:
                                        p.SetValue(t, value, null);
                                        break;
                                }
                                #endregion
                            }
                            catch
                            {
                                //throw (new Exception(ex.Chatroom));  
                            }
                        }
                    }
                }
            }
            return t;
        }
        #endregion 

        #region DataReader转List<T>
        /// <summary>  
        /// DataReader转List<T>  
        /// </summary>  
        /// <typeparam name="T">数据类型</typeparam>  
        /// <param name="dr">DataReader</param>  
        /// <returns>List数据集</returns>  
        public static List<T> DataReaderToList<T>(IDataReader dr) where T : new()
        {
            List<T> tList = new List<T>();
            if (dr == null) return tList;
            T t1 = new T();
            // 获得此模型的公共属性  
            PropertyInfo[] propertys = t1.GetType().GetProperties();
            using (dr)
            {
                List<string> listFieldName = new List<string>(dr.FieldCount);
                for (int i = 0; i < dr.FieldCount; i++)
                {
                    listFieldName.Add(dr.GetName(i).ToLower());
                }
                while (dr.Read())
                {
                    T t = new T();
                    foreach (PropertyInfo p in propertys)
                    {
                        string columnName = p.Name;
                        if (listFieldName.Contains(columnName.ToLower()))
                        {
                            // 判断此属性是否有Setter或columnName值是否为空  
                            object value = dr[columnName];
                            if (!p.CanWrite || value is DBNull || value == DBNull.Value) continue;
                            try
                            {
                                #region SetValue
                                SetPropertyValue<T>(p, t, value);
                                switch (p.PropertyType.ToString())
                                {
                                    case "System.String":
                                        p.SetValue(t, Convert.ToString(value), null);
                                        break;
                                    case "System.Int32":
                                        p.SetValue(t, Convert.ToInt32(value), null);
                                        break;
                                    case "System.DateTime":
                                        p.SetValue(t, Convert.ToDateTime(value), null);
                                        break;
                                    case "System.Boolean":
                                        p.SetValue(t, Convert.ToBoolean(value), null);
                                        break;
                                    case "System.Double":
                                        p.SetValue(t, Convert.ToDouble(value), null);
                                        break;
                                    case "System.Decimal":
                                        p.SetValue(t, Convert.ToDecimal(value), null);
                                        break;
                                    default:
                                        p.SetValue(t, value, null);
                                        break;
                                }
                                #endregion
                            }
                            catch
                            {

                            }
                        }
                    }
                    tList.Add(t);
                }
            }
            return tList;
        }
        #endregion  

        private static void SetPropertyValue<T>(PropertyInfo p, T t, object value)
        {
            switch (p.PropertyType.ToString())
            {
                case "System.String":
                    p.SetValue(t, Convert.ToString(value), null);
                    break;
                case "System.Int32":
                    p.SetValue(t, Convert.ToInt32(value), null);

                    break;
                case "System.DateTime":
                    p.SetValue(t, Convert.ToDateTime(value), null);
                    break;
                case "System.Boolean":
                    p.SetValue(t, Convert.ToBoolean(value), null);
                    break;
                case "System.Double":
                    p.SetValue(t, Convert.ToDouble(value), null);
                    break;
                case "System.Decimal":
                    p.SetValue(t, Convert.ToDecimal(value), null);
                    break;
                default:
                    p.SetValue(t, value, null);
                    break;
            }
        }

        #region 泛型集合转DataTable
        /// <summary>  
        /// 泛型集合转DataTable  
        /// </summary>  
        /// <typeparam name="T">集合类型</typeparam>  
        /// <param name="entityList">泛型集合</param>  
        /// <returns>DataTable</returns>  
        public static DataTable ListToDataTable<T>(IList<T> entityList)
        {
            if (entityList == null) return null;
            DataTable dt = CreateTable<T>();
            Type entityType = typeof(T);
            //PropertyInfo[] properties = entityType.GetProperties();  
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entityType);
            foreach (T item in entityList)
            {
                DataRow row = dt.NewRow();
                foreach (PropertyDescriptor property in properties)
                {
                    row[property.Name] = property.GetValue(item);
                }
                dt.Rows.Add(row);
            }

            return dt;
        }

        #endregion

        #region 创建DataTable的结构
        private static DataTable CreateTable<T>()
        {
            Type entityType = typeof(T);
            //PropertyInfo[] properties = entityType.GetProperties();  
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entityType);
            //生成DataTable的结构  
            DataTable dt = new DataTable();
            foreach (PropertyDescriptor prop in properties)
                dt.Columns.Add(prop.Name);

            return dt;
        }


        #endregion

        #region DataRow转实体
        /// <summary>  
        /// DataRow转实体  
        /// </summary>  
        /// <typeparam name="T">数据型类</typeparam>  
        /// <param name="dr">DataRow</param>  
        /// <returns>模式</returns>  

        public static T DataRowToModel<T>(DataRow dr) where T : new()
        {
            //T t = (T)Activator.CreateInstance(typeof(T));  
            T t = new T();
            if (dr == null) return default(T);
            // 获得此模型的公共属性  
            PropertyInfo[] propertys = t.GetType().GetProperties();
            DataColumnCollection Columns = dr.Table.Columns;
            foreach (PropertyInfo p in propertys)
            {
                string columnName = p.Name;//如果不用属性，数据库字段对应model属性,就用这个  
                if (Columns.Contains(columnName))
                {
                    // 判断此属性是否有Setter或columnName值是否为空  
                    object value = dr[columnName];
                    if (!p.CanWrite || value is DBNull || value == DBNull.Value) continue;
                    try
                    {
                        #region SetValue
                        switch (p.PropertyType.ToString())
                        {
                            case "System.String":
                                p.SetValue(t, Convert.ToString(value), null);
                                break;
                            case "System.Int32":
                                p.SetValue(t, Convert.ToInt32(value), null);
                                break;
                            case "System.Int64":
                                p.SetValue(t, Convert.ToInt64(value), null);
                                break;
                            case "System.DateTime":
                                p.SetValue(t, Convert.ToDateTime(value), null);
                                break;
                            case "System.Boolean":
                                p.SetValue(t, Convert.ToBoolean(value), null);
                                break;
                            case "System.Double":
                                p.SetValue(t, Convert.ToDouble(value), null);
                                break;
                            case "System.Decimal":
                                p.SetValue(t, Convert.ToDecimal(value), null);
                                break;
                            default:
                                p.SetValue(t, value, null);
                                break;
                        }
                        #endregion
                    }
                    catch (Exception ex)
                    {

                        continue;
                        /*使用 default 关键字，此关键字对于引用类型会返回空，对于数值类型会返回零。对于结构， 
                         * 此关键字将返回初始化为零或空的每个结构成员，具体取决于这些结构是值类型还是引用类型*/
                    }
                }
            }
            return t;
        }
        #endregion

        #region DataTable转List<T>
        /// <summary>  
        /// DataTable转List<T>  
        /// </summary>  
        /// <typeparam name="T">数据项类型</typeparam>  
        /// <param name="dt">DataTable</param>  
        /// <returns>List数据集</returns>  
        public static IList<T> DataTableToList<T>(DataTable dt) where T : new()
        {
            IList<T> tList = new List<T>();
            if (dt != null && dt.Rows.Count > 0)
            {
                foreach (DataRow dr in dt.Rows)
                {
                    T t = DataRowToModel<T>(dr);
                    tList.Add(t);
                }
            }
            return tList;
        }
        #endregion


        #region DataReader转DataSet方法
        public static DataSet ConvertDataReaderToDataSet(IDataReader reader)
        {
            DataSet dataSet = new DataSet();
            do
            {
                DataTable schemaTable = reader.GetSchemaTable();
                DataTable dataTable = new DataTable();
                if (schemaTable != null)
                {
                    for (int i = 0; i < schemaTable.Rows.Count; i++)
                    {
                        DataRow dataRow = schemaTable.Rows[i];
                        string columnName = (string)dataRow["ColumnName"];
                        DataColumn column = new DataColumn(columnName, (Type)dataRow["DataType"]);
                        dataTable.Columns.Add(column);
                    }
                    dataSet.Tables.Add(dataTable);
                    while (reader.Read())
                    {
                        DataRow dataRow = dataTable.NewRow();
                        for (int i = 0; i < reader.FieldCount; i++)
                        {
                            dataRow[i] = reader.GetValue(i);
                        }
                        dataTable.Rows.Add(dataRow);
                    }
                }
                else
                {
                    DataColumn column = new DataColumn("RowsAffected");
                    dataTable.Columns.Add(column);
                    dataSet.Tables.Add(dataTable);
                    DataRow dataRow = dataTable.NewRow();
                    dataRow[0] = reader.RecordsAffected;
                    dataTable.Rows.Add(dataRow);
                }
            }
            while (reader.NextResult());
            return dataSet;
        }
        #endregion
    }

    /// </summary>  
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
    public class DBColumn : Attribute
    {
        private string _colName;
        /// <summary>  
        /// 数据库字段  
        /// </summary>  
        public string ColName
        {
            get { return _colName; }
            set { _colName = value; }
        }
        /* 
     AttributeTargets 枚举  
     成员名称 说明  
     All 可以对任何应用程序元素应用属性。   
     Assembly 可以对程序集应用属性。   
     Class 可以对类应用属性。   
     Constructor 可以对构造函数应用属性。   
     Delegate 可以对委托应用属性。   
     Enum 可以对枚举应用属性。   
     Event 可以对事件应用属性。   
     Field 可以对字段应用属性。   
     GenericParameter 可以对泛型参数应用属性。   
     Interface 可以对接口应用属性。   
     Method 可以对方法应用属性。   
     Module 可以对模块应用属性。 注意  
     Module 指的是可移植的可执行文件（.dll 或 .exe），而非 Visual Basic 标准模块。 
     Parameter 可以对参数应用属性。   
     Property 可以对属性 (Property) 应用属性 (Attribute)。   
     ReturnValue 可以对返回值应用属性。   
     Struct 可以对结构应用属性，即值类型  
         */

        /* 
         这里会有四种可能的组合：  

  [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false ]  
  [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false ]  
  [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true ]  
  [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true ] 

　　    第一种情况：  

　　    如果我们查询Derive类，我们将会发现Help特性并不存在，因为inherited属性被设置为false。 

　　    第二种情况： 

　　    和第一种情况相同，因为inherited也被设置为false。 

　　    第三种情况： 

　　    为了解释第三种和第四种情况，我们先来给派生类添加点代码：  

  [Help("BaseClass")]  
  public class Base  
  {  
  }  
  [Help("DeriveClass")]  
  public class Derive : Base  
  {  
  } 

　　    现在我们来查询一下Help特性，我们只能得到派生类的属性，因为inherited被设置为true，但是AllowMultiple却被设置为false。因此基类的Help特性被派生类Help特性覆盖了。 

　　    第四种情况： 

　　    在这里，我们将会发现派生类既有基类的Help特性，也有自己的Help特性，因为AllowMultiple被设置为true。 
         */
    }
}
